home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-01-11 | 9.8 KB | 435 lines | [TEXT/R*ch] |
- //
- // from 'ADB Key Spy' • Pete Gontier • gurgle@apple.com
- // Macintosh Developer Technical Support
- // © 1995,1996 Apple Computer, Inc.
- //
- // Changes:
- //
- // when who what
- // --------------------------------------------------------------
- // 01/11/96 PG copied from another project,
- // merged with various parts of old
- // ADB Key Spy
- //
-
- #ifndef __DEVICES__
- # include <Devices.h>
- #endif
-
- #ifndef __RESOURCES__
- # include <Resources.h>
- #endif
-
- #ifndef __MEMORY__
- # include <Memory.h>
- #endif
-
- #ifndef __LOWMEM__
- # include <LowMem.h>
- #endif
-
- #ifndef __A4STUFF__
- # include <A4Stuff.h>
- #endif
-
- #include "ADBKS Common.h"
- #include "ADBKS csCodes.h"
-
- //
- // vKeyboardServiceRoutineAsm
- //
- // This is a declaration for a function which is in fact
- // never called from C but only by ADB and consists of 68K
- // assembly. However, I pass the thing around enough that
- // it was convenient to define a type for it.
- //
-
- typedef asm void (vKeyboardServiceRoutineAsm) (void);
-
- //
- // dCtlFlags
- //
- // These are the device control entry flags for the driver.
- // Compiler doesn't allow me to specify them with quite enough
- // flexibility (i.e. none), and I don't want to put a manual
- // resource edit into the build process, so I have code do it.
- //
-
- const short dCtlFlags = dRAMBasedMask | dCtlEnableMask | dStatEnableMask;
-
- enum
- {
- //
- // Some miscellaneous quantities needed for installing a driver
- // into the unit table which for whatever reason do not
- // appear in <Devices.h>.
- //
-
- kMaxUTEntries = 128, // maximum size of unit table
- kMinUnitNum = 48 // lowest unit number we can use
- };
-
- static pascal OSErr GrowUnitTable (void)
- {
- //
- // Called when there are no unused slots in unit table.
- // Expands table by 4 entries.
- //
-
- OSErr err = noErr;
- short oldUnitEntryCount = LMGetUnitTableEntryCount ( );
- short newUnitEntryCount;
-
- if (oldUnitEntryCount < kMinUnitNum)
- newUnitEntryCount = 64;
- else
- newUnitEntryCount = oldUnitEntryCount + 4;
-
- if (newUnitEntryCount > kMaxUTEntries)
- err = unitTblFullErr;
- else
- {
- Ptr newUnitTableBase = NewPtrSysClear (newUnitEntryCount * sizeof(long));
- if (!(err = MemError ( )))
- {
- Ptr oldUnitTableBase = LMGetUTableBase ( );
-
- BlockMove (oldUnitTableBase, newUnitTableBase, oldUnitEntryCount * 4);
- LMSetUTableBase (newUnitTableBase);
- LMSetUnitTableEntryCount (newUnitEntryCount);
- DisposePtr (oldUnitTableBase);
- }
- }
-
- return err;
- }
-
- static pascal OSErr DriverInstall (Handle drvrHandle, short drvrRefNum)
- {
- //
- // Creates a DCtlHandle and poulates its fields to describe driver to be installed.
- // Installs new DCtlHandle into unit table.
- //
-
- OSErr err = noErr;
-
- ReserveMem (sizeof (DCtlEntry));
- if (!(err = MemError ( )))
- {
- DCtlHandle dceHandle = (DCtlHandle) NewHandleSysClear (sizeof(DCtlEntry));
- if (!(err = MemError ( )))
- {
- short unitNum = -1 * (drvrRefNum + 1);
- DCtlHandle *unitTable = (DCtlHandle *) LMGetUTableBase ( );
-
- (**dceHandle).dCtlDriver = (Ptr) drvrHandle;
- (**dceHandle).dCtlFlags |= dCtlFlags;
- (**dceHandle).dCtlRefNum = drvrRefNum;
-
- unitTable [unitNum] = dceHandle;
- }
- }
-
- return err;
- }
-
- static pascal short GetUnusedDrvrRefNum (void)
- {
- //
- // Attempts to obtain an unused driver slot.
- //
-
- DCtlHandle *unitTable = (DCtlHandle *) LMGetUTableBase ( );
- short unitEntryCount = LMGetUnitTableEntryCount ( );
- short unitNumber = kMinUnitNum;
- short drvrRefNum = 0;
-
- while (unitTable[unitNumber] && unitNumber < unitEntryCount)
- ++unitNumber;
- if (!unitTable[unitNumber])
- drvrRefNum = -1 * (unitNumber + 1);
-
- return drvrRefNum;
- }
-
- static pascal OSErr GetDrvrRefNum (short *drvrRefNum)
- {
- //
- // Attempts to obtain an unused driver slot.
- // If an empty slot cannot be found, attempts to allocate more slots.
- //
-
- OSErr err = noErr;
-
- if (LMGetUnitTableEntryCount ( ) < kMinUnitNum)
- err = GrowUnitTable ( );
-
- if (!err)
- if (!(*drvrRefNum = GetUnusedDrvrRefNum ( )))
- if (!(err = GrowUnitTable ( )))
- if (!(*drvrRefNum = GetUnusedDrvrRefNum ( )))
- err = unitTblFullErr;
-
- return err;
- }
-
- static pascal OSErr GetKMAP (tKeyboardInfo *kbInfo, char devType)
- {
- //
- // GetKMAP
- //
- // The 'KMAP' resources map raw key codes to virtual key codes.
- // To make it possible for the service routine to easily perform
- // this mapping, we toss a handle to the appropriate 'KMAP'
- // resource into each keyboard info record.
- //
- // The resource is marked locked, so it's interrupt-safe.
- // The resource is marked system-heap, which is what we want
- // because we are an INIT and our heap will disappear soon.
- //
- // One is not supposed to release resources which potentially come from
- // the System file because they might be shared. Thus, we get our resource
- // and keep it ("leak" it). If you have 'KMAP' resources in some other file
- // for some reason, then you might want to call HomeResFile here to help
- // you decide whether to release the resource.
- //
-
- OSErr err = noErr;
-
- const ResType kmapResType = 'KMAP';
-
- tKeyMapResourceH kmapH = (tKeyMapResourceH) GetResource (kmapResType, devType);
- err = ResError ( );
- if (err == resNotFound || !kmapH)
- {
- kmapH = (tKeyMapResourceH) GetResource (kmapResType, 0);
- err = ResError ( );
- if (err == resNotFound)
- {
- err = noErr;
- kmapH = nil; // just to be sure
- }
- }
-
- kbInfo->keyMapResH = kmapH;
-
- return err;
- }
-
- static pascal OSErr AcquireKeyboards
- (vKeyboardServiceRoutineAsm *serviceRoutine, tKeyboardInfoP *keyboardInfoList)
- {
- //
- // Walks the ADB device list and patches the service routine
- // of each keyboard so that an extra (internal) key map is maintained.
- // A block of memory is allocated via NewPtr for each keyboard.
- // Blocks are strung together into a list and returned.
- //
-
- OSErr err = noErr;
-
- ADBSetInfoBlock siBlock;
- ADBDataBlock adbInfo;
-
- short adbCount = CountADBs ( );
-
- *keyboardInfoList = nil;
-
- while (adbCount)
- {
- ADBAddress adbAddress = GetIndADB (&adbInfo, adbCount);
-
- if (adbAddress < 0)
- {
- DebugStr ("\p adbAddress < 0 ?");
- err = paramErr;
- break;
- }
-
- if (adbInfo.origADBAddr == 2) // 2 == keyboard
- {
- //
- // allocate a new record to track old service proc addresses
- //
-
- tKeyboardInfo *newKeyboardInfo =
- (tKeyboardInfo *) NewPtrSysClear (sizeof (tKeyboardInfo));
- err = MemError ( );
- if (err) break;
-
- //
- // fill in the new record and get ready to insert it into our list
- //
-
- err = GetKMAP (newKeyboardInfo, adbInfo.devType);
- if (err)
- {
- DisposePtr ((Ptr) newKeyboardInfo);
- break;
- }
-
- newKeyboardInfo->dbDataAreaAddr = adbInfo.dbDataAreaAddr;
- newKeyboardInfo->dbServiceRtPtr = adbInfo.dbServiceRtPtr;
- newKeyboardInfo->next = *keyboardInfoList;
-
- //
- // replace the device's service routine and data pointer
- //
-
- siBlock.siService = (ADBServiceRoutineUPP) serviceRoutine;
- siBlock.siDataAreaAddr = (Ptr) newKeyboardInfo;
-
- err = SetADBInfo (&siBlock, adbAddress);
- if (err)
- {
- DisposePtr ((Ptr) newKeyboardInfo);
- break;
- }
-
- //
- // insert the new record into our list
- //
-
- *keyboardInfoList = newKeyboardInfo;
- }
-
- --adbCount;
- }
-
- return err;
- }
-
- static pascal OSErr GetServiceRoutine (vKeyboardServiceRoutineAsm **ksra)
- {
- //
- // Loads and detaches the ADB service routine code resource.
- // Produces the ADB service routine address.
- // A copy of the resource stays loaded; call DisposeHandle to free it.
- //
-
- OSErr err = noErr;
-
- //
- // Assume AKSR 128 is system heap, locked, pre-load.
- //
-
- Handle serviceRoutineH = Get1Resource ('AKSR',128);
-
- *ksra = nil;
-
- if (!(err = ResError ( )))
- {
- DetachResource (serviceRoutineH);
- if (!(err = ResError ( )))
- *ksra = (vKeyboardServiceRoutineAsm *) *serviceRoutineH;
- else
- ReleaseResource (serviceRoutineH);
- }
-
- return err;
- }
-
- static pascal OSErr AcquireKeyboardsAndLinkToDriver (ConstStr255Param myDriverName)
- {
- //
- // Gets the address of the service routine.
- // Calls AquireKeyboards to patch all keyboard ADB service routines
- // and obtain a list of patched keyboard ADB info records.
- // Tells driver about this list.
- //
-
- short drvrRefNum;
-
- OSErr err = OpenDriver (myDriverName, &drvrRefNum);
-
- if (!err)
- {
- OSErr err2 = noErr;
- vKeyboardServiceRoutineAsm *ksra = nil;
- if (!(err = GetServiceRoutine (&ksra)))
- {
- tKeyboardInfo *keyboardInfoList = nil;
- err = AcquireKeyboards (ksra, &keyboardInfoList);
-
- //
- // Even if there was an error, there might be a partial list,
- // so we attempt to install it.
- //
-
- if (keyboardInfoList)
- {
- err2 = Control (drvrRefNum,kControlCode_SetKeyboardInfoList,&keyboardInfoList);
- if (!err) err = err2;
- }
- }
-
- //
- // Close the driver no matter what once it's been opened.
- // However, don't report errors on close unless nothing else
- // has gone wrong first.
- //
-
- err2 = CloseDriver (drvrRefNum);
- if (!err) err = err2;
- }
-
- return err;
- }
-
- static pascal OSErr GetAndInstallMyDriver (ConstStr255Param myDriverName)
- {
- //
- // Makes sure the driver is not already installed.
- // Loads it and installs it.
- //
-
- short drvrRefNum;
- OSErr err = OpenDriver (myDriverName, &drvrRefNum);
- if (!err)
- {
- CloseDriver (drvrRefNum);
- err = dupFNErr; // best approximation
- }
- else
- {
- Handle driverHandle = Get1Resource ('Drvr', 48);
- if (!(err = ResError ( )) && driverHandle)
- {
- DetachResource (driverHandle);
- err = ResError ( );
- if (err)
- ReleaseResource (driverHandle);
- else
- {
- short drvrRefNum = 0;
-
- **((short **) driverHandle) |= dCtlFlags;
-
- err = GetDrvrRefNum (&drvrRefNum);
-
- if (err)
- DisposeHandle (driverHandle);
- else
- {
- err = DriverInstall (driverHandle, drvrRefNum);
-
- if (err)
- DisposeHandle (driverHandle);
- }
- }
- }
- }
-
- return err;
- }
-
- void main (void)
- {
- long oldA4 = SetCurrentA4 ( );
- const unsigned char *myDriverName = "\p.adb_key_spy";
- OSErr err = GetAndInstallMyDriver (myDriverName);
- if (!err) err = AcquireKeyboardsAndLinkToDriver (myDriverName);
- if (err) SysBeep (10);
- SetA4 (oldA4);
- }
-